![自社コーポレートサイトにサイト内検索を導入しました](https://images.ctfassets.net/ct0aopd36mqt/1dD7b8HkT2sbiJzUIewMTD/e5cdc6f33c4fdd9d798f11a4564612ff/eyecatch_developersio_darktone_1200x630.jpg)
自社コーポレートサイトにサイト内検索を導入しました
Google Site Search が 4月1日にサービス終了します。読者の中には移行先に奔走された方もいらっしゃるのではないでしょうか?そんな中、先日、自社コーポレートサイトにサイト内検索を独自実装で導入しました。比較的低コストで導入できたのでやったことをご紹介します。
背景
弊社クラスメソッドのコーポレートサイトは全て静的コンテンツです。WordPress プラグインの StaticPress により、静的コンテンツを生成し、S3 にホスティングし、CloudFront から配信しています。それにより、全て静的コンテンツなのでキャッシュヒット率が高く高速なレスポンスができ、インフラコスト、運用コストも低く運用できています。
そんなわけでコンテンツは全て静的コンテンツです。検索できません。しかし弊社のコーポレートサイトは 700近くのページがあります。ユーザーがより閲覧したいページに辿り着けるようにサイト内検索を導入したかったです。
Googleカスタム検索エンジンがあるじゃん?
一時期は弊社コーポレートサイトでも無償の Google カスタム検索エンジンを利用していました。が、今は撤去しています。Google カスタム検索エンジンはページに検索窓を置くだけで Google の検索エンジンを使って、検索できます。例えば、弊社のコーポレートサイトから検索したいようであれば、classmethod.jp
のドメイン下にあるコンテンツだけに絞って検索してくれ、Google 検索ライクな検索結果ページを表示します。非常に便利です。ただし、Googleカスタム検索エンジンは広告が表示されます。個人サイトであれば全然問題とならないのですが、弊社サイトの検索結果に同業他社の広告が表示されるのは好ましくありません。広告が表示されない Google Site Search は冒頭に書いた通り、サービス終了となります。
成果物
まずは簡単にどのようなことが追加されたのか、スクリーンショットでご紹介します。
検索フォームの設置
検索結果ページ
実にシンプルです。
サイト内検索のアーキテクチャ
続いて、ユーザーがサイト内検索を利用する部分と、検索エンジンにデータ連携する構成図です。AWS マネージドサービス活用しまくりです。
細かいことは別エントリでご紹介します。本エントリでは簡単にポイントを絞って説明します。
既存環境の変更は限りなく少なく
サイト内検索導入に伴いアプリケーションサーバの導入はしたくなかったため、S3 静的ウェブサイトホスティングのまま Javascript + Elasticsearch でサイト内検索を実装しました。フロント側は各ページのヘッダ部に検索フォーム追加して、検索結果ページと検索結果をレンダリングする Javascript の実装だけ済みました。
検索エンジンに Elasticseach を利用
検索エンジンには Elasticsearch を利用しています。
Elasticsearch 採用ポイント
- 日本語の Web ページを検索することになるので、自然言語特有の言い回しの正規化や、HTML タグのインデックス除去などネイティブの機能で対応できる
- Web API ベースでデータを取得できるため、アプリケーションサーバを立てなくても、フロントエンドから直接検索できる
(何より今回のサイト内検索自体は私が全文検索用途に利用する Elasticsearch を自由に触れる環境が欲しかったのが目的で声を上げた)
Elasticsearch にデータ同期するバッチの実装
Web ページを Elasticsearch に取り込むために日次でバッチを実行しています。バッチによりコーポレートサイトのトップページからリンクをクロールして、各ページの URL、タイトル、ディスクリプション、変更日、コンテンツをスクレイピングして、Elasticsearch へインデキシングしています。プログラムは Python のクロール、スクレイピングフレームワークの Scrapy を利用していて、メインの処理は 100〜200行ぐらいの実装しかしていません。現在は同時にリンク切れのチェックやコンテンツのチェックをしてマーケティング部に通知する機能も兼ねています。
AWS マネージドサービスを活用した運用コストの低減
導入したはいいが、運用がのしかかってくるのは好ましくありません。そこでバッチ実行環境は AWS Batch、Elasticsearch は Amazon Elasticsearch Service、スケジューラは CloudWatch Events を利用しています。AWS Batch はバッチ実行時にのみインスタンスが起動し、バッチが終了すると自動で停止します。それによりインスタンスの障害や、メンテナンスもほとんど気にする必要がありません。またバッチ実行時間のみが課金対象となり、AWS 利用費を削減できます。Amazon Elasticsearch Service はマネージドサービスであり、障害が発生しても自動で復旧してくれます。またクラスタ化することで可用性を高めることも簡単です。仮に Elasticsearch のデータが吹き飛ぶような障害が発生してもデータ同期バッチを実行することで簡単に復旧できます。
Amazon Elasticsearch Service によるセキュリティ
Amazon Elasticsearch Service はアクセスポリシーによってセキュリティを制御できます。IPアドレス、HTTP メソッド、URL パスなどによって制御できます。コーポレートサイトのサイト内検索ではサーチテンプレートによる検索のエンドポイントのみをパブリックに開放することで外部からのインデキシングや、インデックス設定の参照、負荷が高くなるような検索・集計処理の実行を防いでいます。
CI/CD パイプライン
上の構成図には含まれていませんが、CodePipeline、CodeBuild を利用して、自動テスト、Docker イメージの作成/ECR へのプッシュ、Elasticsearch へのテンプレートのデプロイを実施しています。
CI/CD パイプラインに関しては下記エントリをご参照ください。
- CodeBuild で Amazon Linux 2 の Python 3 アプリケーションの Docker イメージを作成する
- Amazon Elasticsearch Service を継続的デリバリする
今後の展望
せっかく Elasticsearch を導入できたので個人的な趣味、いやコーポレートサイトの利便性向上のために検索機能を高機能にしたいと思っています。
カテゴリによるフィルタリング
多くの人は検索結果の上位数十件、1, 2ページぐらいしか見ないと思います。そこで検索結果からカテゴリを絞ることでユーザーが本当に閲覧したいサイトに行き着きやすくすることができます。Elasticsearch では検索結果からのカテゴリ提示、カテゴリのフィルタリングを簡単に実装することができます。こちらはほぼ実装が完了しているので近々リリース予定です。
検索サジェスト
検索キーワード入力時にキーワードを補完します。検索結果から探さなくても目的のページに辿り着きやすくなります。Elasticsearch はサジェストを提示する機能があります。
「もしかして」
typo などで検索結果がなかった時に本来検索したかったであろうキーワードを提示します。こちらも Elasticsearch のサジェスト機能にあります。
まとめ
既存のコーポレートサイトにほとんど手を加えず、簡単にサイト内検索を実装できました。Elasticsearch の設計や、バッチの実装はもう少し別記事に詳細を書きたいと思います。